package com.birdboot.core;

import com.birdboot.annotations.Controller;
import com.birdboot.annotations.RequestMapping;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

/**
 *     V18新增
 *     在SpringMVC框架中使用这个类维护请求与对应的Controller处理业务方法的对应关系
 *
 *
 *     具体就是生成一个Map保存controller包中的所有的类和方法
 */
public class HandlerMapping {
    /*
    保存请求路径与对应的处理方法
    key:请求路径
    value:处理该请求的某Controller中的某个方法
     */
    private static Map<String, Method> mapping = new HashMap<>();
    /*
        开发中不建议在静态块中直接堆代码,可读性差.
        可以将要做的事情封装为一个方法,用方法名概括代码的含义,然后在这里调用.
        如果是多件事,可以定义多个方法来处理,并在这里陆续调用.
     */
    static {
        initMapping();
    }
    // 扫描controller包中所有Controller（被@Controller标注的类）中的所有的处理方法（被@RequestMapping标注的方法）
    // 根据其对应的路径作为key,该方法对象作为value全部保存到mapping中.
    private static void initMapping(){
        try {
            // 1、类加载路径
            File baseDir = new File(HandlerMapping.class.getClassLoader().getResource(".").toURI());// 定位类加载路径（固定写法）
            // 2、通过类加载路径定位项目中的controller包
            File dir = new File(baseDir, "com/birdboot/controller");
            String packName = "com.birdboot.controller";
            File[] subs = dir.listFiles(f -> f.getName().endsWith(".class"));
            for (File sub : subs) {
                // 根据class文件名来获取类名
                String fileName = sub.getName();
                String className = fileName.substring(0, fileName.indexOf("."));// substring(beginIndex,endIndex);;;indexOf(".")返回"."的数组下标
                Class cls = Class.forName(packName + "." + className);

                // 判断该类是否被注解@Contoller标注
                if (cls.isAnnotationPresent(Controller.class)) {
                    // Object obj = cls.newInstance();
                    // 扫描里面所有的方法，并找到有注解@RequsetMapping的方法
                    Method[] methods = cls.getDeclaredMethods();
                    for (Method method : methods) {
                        if (method.isAnnotationPresent(RequestMapping.class)) {//判断是否被注解@RequestMapping修饰
                            // 通过@RequestMmapping注解获取上面的参数（即该方法的请求路径）
                            RequestMapping rm = method.getAnnotation(RequestMapping.class);
                            String value = rm.value();
                            // 将该方法以及其对应的路径存入mapping中
                            mapping.put(value, method);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据请求路径获取对应的处理方法
     * @param path
     * @return
     */
    public static Method getMethod(String path){
        return mapping.get(path);
    }
}
